#include "study.h"
#include <iostream>
#include <iomanip>      // std::setw
#include <math.h>       /* fabs */
#include <limits>
#include "math_ext.h"

study::study() :
  signal_count_max(0),
  last_in_sig_id(0),
  last_out_sig_id(0)

{
}

study::~study()
{
}

//void study::setneuronet(neuron *pin)
//{
//  pneuron = pin;
//}

void study::setsignacountmax(int count_max)
{
    signal_count_max = count_max;
}

void study::addinstudysignal(ntype::signal_t * pin)
{
   study_in_signal.push_back(pin);

   psignal_study_forward->setstudysignalid(last_in_sig_id);
   psignal_study_forward->setinsignal(pin);
   last_in_sig_id ++;

}

//void study::setneuroncount(ntype::neuroncount_t val)
//{
//   neuron_count_max = val;
//}

void study::addexpextedsignal(ntype::signal_t *pin)
{
   study_expeced_signal.push_back(pin);

   psignal_study_back->setstudysignalid(last_out_sig_id);
   psignal_study_back->setexpectedsignal(pin);
   last_out_sig_id ++;

}

void study::setsendsignalfstudy(sendsignal_f_study *pin)
{
   psignal_study_forward = pin;
}

void study::setsendsignalbstudy(sendsignal_b_study *pin)
{
  psignal_study_back = pin;
}

void study::setmaxerror(ntype::error_t din)
{
  max_study_error = din;
}

ntype::error_t study::getmaxerror()
{
  return max_study_error;
}

void study::setstudyciclecount(uint32_t iin)
{
  study_cicle_count_max = iin;
}

uint32_t study::getstudyciclecount()
{
  return study_cicle_count_max;
}

//typedef std::numeric_limits< double > dbl;
void study::printNeuroNet(ntype::signalid_t signalid)
{
    const static size_t fieldWidth = 13;
    const static int    fieldPrecision = 5;
//    std::cout << " ===== study mode ===== " << std::endl;

    std::cout << std::setw(fieldWidth) << std::left << "signal.id |"
              << std::setw(fieldWidth) << std::left << "max.err   |"
              << std::endl;
    std::cout
              << std::setw(fieldWidth) << std::fixed << std::left << std::setprecision(fieldPrecision) << signalid
              << std::setw(fieldWidth) << std::fixed << std::left << std::setprecision(fieldPrecision) << max_study_error
              << std::endl;


    std::cout << std::setw(fieldWidth) << std::left << "neuron id |"
              << std::setw(fieldWidth) << std::left << "syn id |"
              << std::setw(fieldWidth) << std::left << "w         |"
              << std::setw(fieldWidth) << std::left << "w.back    |"
              << std::setw(fieldWidth) << std::left << "syn.fwd   |"
              << std::setw(fieldWidth) << std::left << "axon.fwd  |"
              << std::setw(fieldWidth) << std::left << "syn.back  |"
              << std::setw(fieldWidth) << std::left << "axon back |"
              << std::setw(fieldWidth) << std::left << "syn.diff  |"
              << std::setw(fieldWidth) << std::left << "axon.error |"
              << std::endl;
    for(ntype::neuroncount_t neuron_count = 0; neuron_count < neuron_count_max; neuron_count ++)
    {
      ntype::synapsecount_t syn_count_max = pneuron[neuron_count].getSynapseCount();
      for(ntype::synapsecount_t synapse_count = 0; synapse_count < syn_count_max; synapse_count ++)
      {
          pneuron[neuron_count].setStudyBufferIndex(signalid);
          std::cout << std::setw(fieldWidth) << std::fixed << std::left << std::setprecision(fieldPrecision) << neuron_count
                    << std::setw(fieldWidth) << std::fixed << std::left << std::setprecision(fieldPrecision) << synapse_count
                    << std::setw(fieldWidth) << std::fixed << std::left << std::setprecision(fieldPrecision) << pneuron[neuron_count].getSynapse(synapse_count).getWeight()
                    << std::setw(fieldWidth) << std::fixed << std::left << std::setprecision(fieldPrecision) << pneuron[neuron_count].clac_back_synapse_w(synapse_count)
                    << std::setw(fieldWidth) << std::fixed << std::left << std::setprecision(fieldPrecision) << pneuron[neuron_count].getSynapse(synapse_count).getFSignalStudy(signalid)
                    << std::setw(fieldWidth) << std::fixed << std::left << std::setprecision(fieldPrecision) << pneuron[neuron_count].getAxon().getFStudySignal(signalid)
                    << std::setw(fieldWidth) << std::fixed << std::left << std::setprecision(fieldPrecision) << pneuron[neuron_count].getSynapse(synapse_count).getBSignalStudy(signalid)
                    << std::setw(fieldWidth) << std::fixed << std::left << std::setprecision(fieldPrecision) << pneuron[neuron_count].getAxon().getBStudySignal(signalid)
                    << std::setw(fieldWidth) << std::fixed << std::left << std::setprecision(fieldPrecision) << fabs(pneuron[neuron_count].getSynapse(synapse_count).getFSignalStudy(signalid)) + fabs(pneuron[neuron_count].getSynapse(synapse_count).getBSignalStudy(signalid))
                    << std::setw(fieldWidth) << std::fixed << std::left << std::setprecision(fieldPrecision) << pneuron[neuron_count].getAxonStudyError()
                    << std::endl;
#if 0
          double diff = (pneuron[neuron_count].getAxon().getFStudySignal(signalid) - pneuron[neuron_count].getAxon().getBStudySignal(signalid));
          double max= std::max(pneuron[neuron_count].getAxon().getBStudySignal(signalid), pneuron[neuron_count].getAxon().getFStudySignal(signalid));
          double div_r = diff / max;

          std::cout << std::setprecision(9) << " 1st: " << pneuron[neuron_count].getAxon().getFStudySignal(signalid)
                    << " 2nd: " << pneuron[neuron_count].getAxon().getBStudySignal(signalid)
                    <<" diff: " << diff << " max: " << max << " div: " << div_r << std::endl;
//          std::cout << "=====" << (pneuron[neuron_count].getAxon().getFStudySignal(signalid) - pneuron[neuron_count].getAxon().getBStudySignal(signalid)) << std::endl;
#endif
      }
      std::cout << std::endl;
    }
    std::cout << "--------------------------------" << std::endl;
}

